#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2017/5/9 上午8:05
# @Author  : zhangzhen
# @Site    : 
# @File    : syn.py
# @Software: PyCharm
import Queue
import sys
import random
import numpy as np
from collections import defaultdict
import pandas as pd
from sklearn.multiclass import OneVsOneClassifier
from sklearn.svm import LinearSVC
from sklearn.svm import SVC
import matplotlib.pyplot as plt
from com.corpus import corpus
from sklearn.multiclass import OneVsRestClassifier
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2

class tree:
    def __init__(self, value, left=None, right=None):
        self.__value = value
        self.__left = left
        self.__right = right

    def get_val(self):
        return self.__value

    def get_left(self):
        return self.__left

    def set_left(self,left):
        self.__left = left

    def get_right(self):
        return self.__right

    def set_right(self,right):
        self.__right = right

    def visitTreeAndGetFeatures(self):
        pool = Queue.Queue()
        pool.put(self)
        res = []
        while not pool.empty():
            tmp = pool.get()
            if tmp.get_left() is not None and tmp.get_right() is not None:
                # print tmp.get_val(), tmp.get_left().get_val(), tmp.get_right().get_val()
                pattern = '('+tmp.get_val()+'('+tmp.get_left().get_val()+')('+tmp.get_right().get_val()+'))'
                res.append(pattern)
                pool.put(tmp.get_left())
                pool.put(tmp.get_right())
            elif tmp.get_left() is not None:
                pool.put(tmp.get_left())
            elif tmp.get_right() is not None:
                pool.put(tmp.get_right())

        if len(res) > 0:
            return '&'.join(res)
        else:
            return 'null'


class syn_utils:
    @staticmethod
    def buildSynTree(root, syntax):
        if syntax is None:
            return None
        left = 0
        right = 0
        split = 0
        for i in range(len(syntax)):
            if syntax[i] == '[':
                left += 1
            if syntax[i] == ']':
                right += 1
            if left == right:
                split = i + 1
                break
        if split == len(syntax):  # 只有一个节点时
            if left < 1 or right < 1:
                return
            syntax = syntax[1:-1]
            cur = syntax.find(' ')
            synVal = syntax[0:cur]
            syntax = syntax[cur + 1:]
            leftNode = tree(synVal)
            root.set_left(leftNode)
            syn_utils.buildSynTree(root.get_left(), syntax)
        elif left > 0 and right > 0:
            leftSyntax = syntax[0:split]
            rightSyntax = syntax[split + 1:]

            leftSyntax = leftSyntax[1:-1]
            rightSyntax = rightSyntax[1:-1]

            left_cur = leftSyntax.find(' ')
            leftVal = leftSyntax[0:left_cur]
            leftSyntax = leftSyntax[left_cur + 1:]
            leftNode = tree(leftVal)
            root.set_left(leftNode)
            syn_utils.buildSynTree(root.get_left(), leftSyntax)

            right_cur = rightSyntax.find(' ')
            rightVal = rightSyntax[0:right_cur]
            rightSyntax = rightSyntax[right_cur + 1:]
            rightNode = tree(rightVal)
            root.set_right(rightNode)
            syn_utils.buildSynTree(root.get_right(), rightSyntax)

    @staticmethod
    def get_syn(synStr):
        if len(synStr) < 5:
            return 'null'
        syntax = synStr[4:-3]
        # print target
        # print synStr
        root = tree('ROOT')
        syn_utils.buildSynTree(root, syntax)
        return root.visitTreeAndGetFeatures()


    @staticmethod
    def load_syn():
        """syn维度 554"""
        syn_pool = list()
        documents = []
        vectorizer = CountVectorizer()  # 该类会将文本中的词语转换为词频矩阵，矩阵元素a[i][j] 表示j词在i类文本下的词频
        transformer = TfidfTransformer()  # 该类会统计每个词语的tf-idf权值
        texts = []
        y = []
        for i in range(7):
            c = corpus.corpus('../../data/', str(i))
            syn_corpus = c.get_syn_corpus()
            documents.append(syn_corpus)
            for line in syn_corpus:
                if len(line) > 0:
                    syn_pool.extend(line.split('&'))
        # 特征库
        syn_pool = list(set(syn_pool))
        for i, ds in enumerate(documents):
            for d in ds:
                if len(d) > 0:
                    ws = d.split('&')
                    feature = [str(syn_pool.index(w)) for w in ws]
                    texts.append(' '.join(feature))
                    y.append(i)
        tfidf = transformer.fit_transform(vectorizer.fit_transform(texts))
        # word = vectorizer.get_feature_names() # 获取对应特征值
        X = tfidf.toarray()
        return X, np.array(y)

def plot(macro_p,macro_r,micro_p,micro_r,tops):

    x = [i for i, v in enumerate(tops)]
    # 创建绘图对象，figsize参数可以指定绘图对象的宽度和高度，单位为英寸，一英寸=80px
    plt.figure(figsize=(8, 4))
    # 在当前绘图对象中画图（x轴,y轴,给所绘制的曲线的名字，画线颜色，画线宽度）
    # 宏平均(macro-average)和微平均(micro-average)
    #
    plt.plot(x, macro_p, 'ro-', label="$macro-precision$", color="red", linewidth=2)
    plt.plot(x, macro_r, 'gv-', label="$macro-recall$", color="green", linewidth=2)
    plt.plot(x, 2*macro_p*macro_r/(macro_p+macro_r), 'bs-', label="$macro-F$", color="blue", linewidth=2)
    plt.plot(x, micro_p, 'ch-', label="$micro-average$", color="black", linewidth=2)
    # plt.plot(x, micro_r, 'mD-', label="$micro-recall$", color="cyan", linewidth=2)
    # plt.plot(x, 2*micro_p*micro_r/(micro_p+micro_r), 'r^-', label="$micro-F$", color="magenta", linewidth=2)
    # X轴的文字
    # plt.xlabel("Time(s)")
    # group_labels = ['10', '40', '80', '100', '120', '150', '180', '200', '220']
    plt.xticks(x, tops, rotation=0)
    # Y轴的文字
    # plt.ylabel("Volt")

    # 图表的标题
    plt.title(u'Classification of Syntactic dependency Features with Different Dimensions')
    # Y轴的范围
    plt.xlim(0, len(tops)+4)
    plt.ylim(0.15, 0.55)
    # 显示图示
    plt.legend()
    plt.grid()
    # 显示图
    plt.show()

if __name__ == '__main__':
    # target = '[ [ [IP [VP [NP [KP [NP [ng ཕ་རོལ་པོ]] [K [kg འི་]]] [N [ng དཔའ་]]] [V [vt འཇོམས་པར་བྱས་]]] [I [T [h པ]]]] [PU [xp །]]] ]'
    # print syn_utils.getSyn(target)

    # 554 维度
    X, y = syn_utils.load_syn()
    macro_p = np.zeros(25)
    macro_r = np.zeros(25)
    micro_p = np.zeros(25)
    micro_r = np.zeros(25)
    # top = 1000  # 特征维度数
    train_num = 400
    test_num = 100  # 文本测试集
    times = 50
    for time in range(times):
        tops = []
        tmp_macro_p = []
        tmp_macro_r = []
        tmp_micro_p = []
        tmp_micro_r = []
        for top in range(50, 550, 20):
            X_new = SelectKBest(chi2, k=top).fit_transform(X, y)
            tops.append(top)
            # 随机选取训练数据 300
            train_index = []
            test_index = []
            type_dict = defaultdict(list)
            # 随机选取各类数据100个
            for k, v in enumerate(y):
                type_dict[v].append(k)
            for k, v in type_dict.iteritems():
                if train_num >= len(type_dict[k]):
                    train_index.extend(type_dict[k])
                else:
                    train_index.extend(random.sample(type_dict[k], train_num))
                test_index.extend(random.sample(type_dict[k], test_num))

            X_train = np.array([X_new[i] for i in train_index])
            y_train = np.array([y[i] for i in train_index])

            X_test = np.array([X_new[i] for i in test_index])
            y_test = np.array([y[i] for i in test_index])

            acc = np.ones(7)
            err = np.ones(7)
            # res = OneVsOneClassifier(LinearSVC(random_state=0)).fit(X_new, y).predict(X_test)
            res = OneVsRestClassifier(LinearSVC(random_state=0)).fit(X_new, y).predict(X_test)
            # print res
            for i, re in enumerate(res):
                if re == y_test[i]:
                    acc[re] += 1
                else:
                    err[re] += 1
            # 宏平均
            ap = np.sum(acc / (err + acc)) / 7
            ar = np.sum(acc / test_num) / 7
            tmp_macro_p.append(ap)
            tmp_macro_r.append(ar)

            # 微平均
            ip = np.sum(acc) / (np.sum(acc) + np.sum(err))
            ir = np.sum(acc) / (7 * test_num)
            tmp_micro_p.append(ip)
            tmp_micro_r.append(ir)

        macro_p += np.array(tmp_macro_p)
        macro_r += np.array(tmp_macro_r)
        micro_p += np.array(tmp_micro_p)
        micro_r += np.array(tmp_micro_r)

    macro_p = macro_p/times
    macro_r = macro_r/times
    micro_p = micro_p/times
    micro_r = micro_r/times

    print "维度", tops
    print "宏准确", macro_p
    print "宏召回率",macro_r
    print "宏F值",2* macro_p * macro_r / (macro_p + macro_r)
    print "微准确率",micro_p
    print "微召回率",micro_r
    print "微F值",2* micro_p * micro_r / (micro_p + micro_r)
    # 绘图操作
    # 绘图操作
    plot(macro_p, macro_r, micro_p, micro_r, tops)
